using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Acme.BookStore.Redis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
using Volo.Abp.DependencyInjection;

namespace Acme.BookStore.Redis
{
    /// <summary>
    /// Redis缓存监控服务，提供缓存性能监控和统计功能
    /// </summary>
    public class RedisCacheMonitorService : ISingletonDependency
    {
        private readonly ILogger<RedisCacheMonitorService> _logger;
        private readonly IConfiguration _configuration;
        private readonly bool _isRedisEnabled;
        private readonly string _redisConfiguration;
        private readonly string _instanceName;

        public RedisCacheMonitorService(
            ILogger<RedisCacheMonitorService> logger,
            IConfiguration configuration)
        {
            _logger = logger;
            _configuration = configuration;
            
            // 读取配置
            _isRedisEnabled = _configuration["Redis:IsEnabled"]?.Equals("true", StringComparison.OrdinalIgnoreCase) == true;
            _redisConfiguration = _configuration["Redis:Configuration"] ?? "localhost:6379";
            _instanceName = _configuration["Redis:InstanceName"] ?? "BookStore";
        }

        /// <summary>
        /// 获取Redis状态信息
        /// </summary>
        public async Task<RedisStatusDto> GetStatusAsync()
        {
            try
            {
                if (!_isRedisEnabled)
                {
                    return new RedisStatusDto
                    {
                        IsEnabled = false,
                        Configuration = _redisConfiguration,
                        InstanceName = _instanceName,
                        Status = "已禁用",
                        Message = "Redis缓存未启用，系统使用内存缓存"
                    };
                }

                // 测试Redis连接，添加重试机制
                ConnectionMultiplexer connection = null;
                int retryCount = 0;
                int maxRetries = 3;
                
                try
                {
                    while (connection == null && retryCount < maxRetries)
                    {
                        try
                        {
                            var options = ConfigurationOptions.Parse(_redisConfiguration);
                            options.AbortOnConnectFail = false;
                            options.ConnectTimeout = 5000;
                            options.SyncTimeout = 10000;
                            
                            connection = await ConnectionMultiplexer.ConnectAsync(options);
                            retryCount++;
                        }
                        catch (Exception ex)
                        {
                            _logger.LogWarning(ex, "尝试连接Redis失败，重试 {RetryCount}/{MaxRetries}", retryCount, maxRetries);
                            if (retryCount >= maxRetries)
                                throw;
                            await Task.Delay(1000); // 延迟1秒后重试
                        }
                    }
                    
                    var startTime = DateTime.Now;
                    var pingResult = await connection.GetDatabase().PingAsync();
                    var latency = (DateTime.Now - startTime).TotalMilliseconds;
                    
                    _logger.LogInformation("成功连接到Redis服务器: {Endpoint}，延迟: {Latency}ms", 
                        _redisConfiguration, latency.ToString("F4"));

                    // 获取所有Redis服务器信息
                    var server = connection.GetServer(connection.GetEndPoints().First());
                    
                    // 获取Redis服务器详细信息
                    var statusInfo = await GetRedisInfoAsync(server);
                    
                    // 获取键统计
                    var keyStats = await GetKeyStatisticsAsync(server);
                    
                    return new RedisStatusDto
                    {
                        IsEnabled = true,
                        Configuration = _redisConfiguration,
                        InstanceName = _instanceName,
                        Status = "运行中",
                        Message = "Redis缓存正常运行",
                        UsedMemory = statusInfo.UsedMemory,
                        MaxMemory = statusInfo.MaxMemory,
                        ConnectedClients = statusInfo.ConnectedClients,
                        TotalCommands = statusInfo.TotalCommands,
                        CacheHitRate = statusInfo.CacheHitRate,
                        TotalKeys = keyStats.TotalKeys,
                        BookStoreKeys = keyStats.BookStoreKeys,
                        KehuListKeys = keyStats.KehuListKeys,
                        KehuSearchKeys = keyStats.KehuSearchKeys,
                        KehuAdvSearchKeys = keyStats.KehuAdvSearchKeys,
                        Latency = $"{latency:F2}ms",
                        // 新增指标
                        UptimeInSeconds = statusInfo.UptimeInSeconds,
                        UptimeInDays = statusInfo.UptimeInDays,
                        MemoryFragmentationRatio = statusInfo.MemoryFragmentationRatio,
                        ExpiredKeysCount = statusInfo.ExpiredKeys,
                        EvictedKeysCount = statusInfo.EvictedKeys,
                        KeyspaceHits = statusInfo.KeyspaceHits,
                        KeyspaceMisses = statusInfo.KeyspaceMisses,
                        RejectedConnections = statusInfo.RejectedConnections
                    };
                }
                finally
                {
                    // 确保连接被正确释放
                    if (connection != null && connection.IsConnected)
                    {
                        connection.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取Redis状态时出错");
                return new RedisStatusDto
                {
                    IsEnabled = false,
                    Configuration = _redisConfiguration,
                    InstanceName = _instanceName,
                    Status = "错误",
                    Message = $"获取Redis状态时出错: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// 清除符合指定模式的缓存键
        /// </summary>
        public async Task<(int count, string message)> ClearCacheAsync(string pattern)
        {
            if (!_isRedisEnabled)
            {
                return (0, "Redis缓存未启用，无法清除缓存");
            }
            
            // 安全检查，防止清除所有键
            if (string.IsNullOrEmpty(pattern) || pattern == "*")
            {
                return (0, "不允许清除所有键，请提供一个更具体的模式");
            }
            
            ConnectionMultiplexer connection = null;
            try
            {
                // 确保模式以BookStore:前缀开始（使用ABP缓存键前缀）
                if (!pattern.StartsWith("BookStore:") && !pattern.StartsWith("*"))
                {
                    pattern = $"BookStore:{pattern}";
                }
                
                var options = ConfigurationOptions.Parse(_redisConfiguration);
                options.AbortOnConnectFail = false;
                options.ConnectTimeout = 5000;
                options.SyncTimeout = 10000;
                
                connection = await ConnectionMultiplexer.ConnectAsync(options);
                var server = connection.GetServer(connection.GetEndPoints().First());
                var db = connection.GetDatabase();
                
                // 获取匹配的键并分批删除
                var keys = server.Keys(pattern: pattern).ToArray();
                var keyCount = keys.Length;
                
                if (keyCount > 0)
                {
                    // 分批删除避免一次性操作太多键
                    const int batchSize = 100;
                    for (int i = 0; i < keyCount; i += batchSize)
                    {
                        var batch = keys.Skip(i).Take(Math.Min(batchSize, keyCount - i)).ToArray();
                        await db.KeyDeleteAsync(batch);
                    }
                    
                    _logger.LogInformation("已清除{Count}个匹配{Pattern}的缓存键", keyCount, pattern);
                    return (keyCount, $"成功清除 {keyCount} 个缓存键");
                }
                else
                {
                    return (0, $"没有找到匹配模式 '{pattern}' 的缓存键");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "清除Redis缓存时出错");
                throw;
            }
            finally
            {
                // 确保连接被正确释放
                if (connection != null && connection.IsConnected)
                {
                    connection.Close();
                }
            }
        }
        
        /// <summary>
        /// 获取Redis性能指标
        /// </summary>
        public async Task<RedisPerformanceMetrics> GetPerformanceMetricsAsync()
        {
            if (!_isRedisEnabled)
            {
                return new RedisPerformanceMetrics
                {
                    IsEnabled = false,
                    Message = "Redis缓存未启用，无法获取性能指标"
                };
            }
            
            ConnectionMultiplexer connection = null;
            try
            {
                var options = ConfigurationOptions.Parse(_redisConfiguration);
                options.AbortOnConnectFail = false;
                options.ConnectTimeout = 5000;
                options.SyncTimeout = 10000;
                
                connection = await ConnectionMultiplexer.ConnectAsync(options);
                var server = connection.GetServer(connection.GetEndPoints().First());
                var db = connection.GetDatabase();
                
                // 测试基本操作性能
                var metrics = new RedisPerformanceMetrics { IsEnabled = true };
                
                // 测试SET操作
                var setTimer = System.Diagnostics.Stopwatch.StartNew();
                for (int i = 0; i < 100; i++)
                {
                    await db.StringSetAsync($"perftest:set:{i}", i.ToString(), TimeSpan.FromSeconds(10));
                }
                setTimer.Stop();
                metrics.SetOperationsPerSecond = 100000 / setTimer.ElapsedMilliseconds;
                
                // 测试GET操作
                var getTimer = System.Diagnostics.Stopwatch.StartNew();
                for (int i = 0; i < 100; i++)
                {
                    await db.StringGetAsync($"perftest:set:{i}");
                }
                getTimer.Stop();
                metrics.GetOperationsPerSecond = 100000 / getTimer.ElapsedMilliseconds;
                
                // 清理性能测试键
                await ClearCacheAsync("perftest:*");
                
                return metrics;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取Redis性能指标时出错");
                return new RedisPerformanceMetrics
                {
                    IsEnabled = false,
                    Message = $"获取Redis性能指标时出错: {ex.Message}"
                };
            }
            finally
            {
                // 确保连接被正确释放
                if (connection != null && connection.IsConnected)
                {
                    connection.Close();
                }
            }
        }
        
        /// <summary>
        /// 添加性能测试数据
        /// </summary>
        public async Task<string> GenerateTestDataAsync(int count = 1000)
        {
            if (!_isRedisEnabled)
            {
                return "Redis缓存未启用，无法生成测试数据";
            }
            
            ConnectionMultiplexer connection = null;
            try
            {
                var options = ConfigurationOptions.Parse(_redisConfiguration);
                options.AbortOnConnectFail = false;
                options.ConnectTimeout = 5000;
                options.SyncTimeout = 10000;
                
                connection = await ConnectionMultiplexer.ConnectAsync(options);
                var db = connection.GetDatabase();
                
                // 生成多种类型的测试数据
                int stringCount = count / 2;
                int hashCount = count / 4;
                int listCount = count / 4;
                
                // 先清理已有测试数据
                await ClearCacheAsync("BookStore:TestData:*");
                
                // 生成字符串类型数据
                for (int i = 0; i < stringCount; i++)
                {
                    await db.StringSetAsync($"BookStore:TestData:String:{i}", 
                        $"TestValue-{Guid.NewGuid()}", 
                        TimeSpan.FromMinutes(30));
                }
                
                // 生成哈希类型数据
                for (int i = 0; i < hashCount; i++)
                {
                    var hashKey = $"BookStore:TestData:Hash:{i}";
                    var fields = new HashEntry[]
                    {
                        new HashEntry("field1", $"value1-{i}"),
                        new HashEntry("field2", $"value2-{i}"),
                        new HashEntry("field3", $"value3-{i}"),
                    };
                    await db.HashSetAsync(hashKey, fields);
                    db.KeyExpire(hashKey, TimeSpan.FromMinutes(30));
                }
                
                // 生成列表类型数据
                for (int i = 0; i < listCount; i++)
                {
                    var listKey = $"BookStore:TestData:List:{i}";
                    await db.ListRightPushAsync(listKey, new RedisValue[] {
                        $"item1-{i}", $"item2-{i}", $"item3-{i}", $"item4-{i}", $"item5-{i}"
                    });
                    db.KeyExpire(listKey, TimeSpan.FromMinutes(30));
                }
                
                return $"已成功生成{count}条测试数据（{stringCount}字符串，{hashCount}哈希，{listCount}列表）";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "生成Redis测试数据时出错");
                return $"生成测试数据时出错: {ex.Message}";
            }
            finally
            {
                // 确保连接被正确释放
                if (connection != null && connection.IsConnected)
                {
                    connection.Close();
                }
            }
        }
        
        #region 私有辅助方法
        
        /// <summary>
        /// 从Redis服务获取信息
        /// </summary>
        private async Task<(string UsedMemory, string MaxMemory, string ConnectedClients, 
            string TotalCommands, string CacheHitRate, string UptimeInDays, 
            string UptimeInSeconds, string MemoryFragmentationRatio, 
            string ExpiredKeys, string EvictedKeys, string KeyspaceHits,
            string KeyspaceMisses, string RejectedConnections)> GetRedisInfoAsync(IServer server)
        {
            string usedMemory = "未知";
            string maxMemory = "未知";
            string connectedClients = "0";
            string totalCommands = "0";
            string keyspaceHits = "0";
            string keyspaceMisses = "0";
            string uptimeInSeconds = "0";
            string uptimeInDays = "0";
            string memFragmentationRatio = "0";
            string expiredKeys = "0";
            string evictedKeys = "0";
            string rejectedConnections = "0";
            
            try
            {
                var rawInfo = await server.InfoAsync();
                
                if (rawInfo.Any())
                {
                    foreach (var section in rawInfo)
                    {
                        foreach (var entry in section)
                        {
                            switch (entry.Key)
                            {
                                case "used_memory_human": usedMemory = entry.Value; break;
                                case "maxmemory_human": maxMemory = entry.Value; break;
                                case "connected_clients": connectedClients = entry.Value; break;
                                case "total_commands_processed": totalCommands = entry.Value; break;
                                case "keyspace_hits": keyspaceHits = entry.Value; break;
                                case "keyspace_misses": keyspaceMisses = entry.Value; break;
                                case "uptime_in_seconds": uptimeInSeconds = entry.Value; break;
                                case "uptime_in_days": uptimeInDays = entry.Value; break;
                                case "mem_fragmentation_ratio": memFragmentationRatio = entry.Value; break;
                                case "expired_keys": expiredKeys = entry.Value; break;
                                case "evicted_keys": evictedKeys = entry.Value; break;
                                case "rejected_connections": rejectedConnections = entry.Value; break;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "获取Redis详细信息失败");
            }
            
            // 计算缓存命中率
            double hitRate = 0;
            if (double.TryParse(keyspaceHits, out var hits) && double.TryParse(keyspaceMisses, out var misses) && (hits + misses) > 0)
            {
                hitRate = hits / (hits + misses) * 100;
            }
            
            return (
                usedMemory, 
                maxMemory, 
                connectedClients, 
                totalCommands,
                $"{hitRate:F2}%",
                uptimeInDays,
                uptimeInSeconds,
                memFragmentationRatio,
                expiredKeys,
                evictedKeys,
                keyspaceHits,
                keyspaceMisses,
                rejectedConnections
            );
        }
        
        /// <summary>
        /// 获取键统计信息
        /// </summary>
        private async Task<(int TotalKeys, int BookStoreKeys, int KehuListKeys, int KehuSearchKeys, int KehuAdvSearchKeys)> 
            GetKeyStatisticsAsync(IServer server)
        {
            int totalKeys = 0;
            int bookStoreKeys = 0;
            int kehuListKeys = 0;
            int kehuSearchKeys = 0;
            int kehuAdvSearchKeys = 0;
            
            try
            {
                // 先获取键总数
                totalKeys = (int)server.DatabaseSize();
                
                // 获取前缀统计 - 避免全量获取键，使用SCAN更高效
                var keys = server.Keys(pattern: "BookStore:*", pageSize: 1000);
                
                // 对键进行分类计数
                foreach (var key in keys)
                {
                    string keyString = key.ToString();
                    bookStoreKeys++;
                    
                    if (keyString.Contains("KehuList"))
                    {
                        kehuListKeys++;
                    }
                    else if (keyString.Contains("KehuSearch"))
                    {
                        kehuSearchKeys++;
                    }
                    else if (keyString.Contains("KehuAdvSearch"))
                    {
                        kehuAdvSearchKeys++;
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "获取Redis键统计信息失败");
            }
            
            return (totalKeys, bookStoreKeys, kehuListKeys, kehuSearchKeys, kehuAdvSearchKeys);
        }
        
        #endregion
    }
} 